package com.android.publicModule.network;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.message.BasicHeader;

import com.android.publicModule.system.SystemInfo;
import com.android.publicModule.tools.Tools;

import android.content.Context;
import android.util.Log;

public class DownloadFile {

	private Context mContext;
	private final static String DEFAULT_SAVE_FILE_DIR = "appDownload";
	private final static String TEMP_FILE_END = ".temp";
    private final static int defaultBlockSize = 180*1024;// 默认分段下载长度每次最多下载180K
    private int blockSize = defaultBlockSize;
    private long downloadFileSize = -1;//下载文件大小
    private boolean isInterrup;//是否终止下载任务
    private DownloadProgress downloadProgress;//下载进度信息类
    private int type;//下载失败的类型
    private String reason;//下载失败的原因
    private String mUrl;//原始下载路径
    private boolean downloadPhone;//是否下载在手机内部存储
    private String sdcardPath;//SD卡的路径
    private String mSavePath;
    private String mId;
    private Object mDownloadInfo;
    private HttpRequest httpRequest;
    
    /**
     * 构造方法
     * @param context
     */
	public DownloadFile(Context context) {
		if(context!=null)
		{
			mContext = context.getApplicationContext();
		}
	}
	
	/**
	 * 设置分段下载长度
	 * @param size
	 */
	public void setBlockSize(int size) {
		blockSize = size;
	}
	
	/**
	 * 返回下载文件的大小
	 * @return
	 */
	public long getDownloadFileSize() {
		return downloadFileSize;
	}
	
	/**
	 * 停止下载
	 */
	public void stopDownload() {
		isInterrup = true;
	}
	
	/**
	 * 设置下载进度及状态回调接口
	 * @param p
	 */
	public void setDownloadProgress(DownloadProgress progress) {
		downloadProgress = progress;
	}
	
	/**
	 * 返回下载失败类型
	 * @return
	 */
	public int getDownloadFailType() {
		return type;
	}
	
	/**
	 * 返回下载失败原因
	 * @return
	 */
	public String getDownloadFailReason() {
		return reason;
	}
	
	/**
	 * 返回最终文件保存路径
	 * @return
	 */
	public String getSavePath() {
		return mSavePath;
	}
	
	public static final int DOWNLOAD_STATE_TYPE_NO_NETWORK = 1;
	public static final int DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED = 2;
	public static final int DOWNLOAD_STATE_TYPE_CONNECT_FAIL = 3;
	
	
	public static final String DOWNLOAD_RESULT_REASON_NO_NETWORK = "网络连接失败！";
	public static final String DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED = "已经成功下载过了！";
	public static final String DOWNLOAD_RESULT_REASON_CONNECT_FAIL = "服务器连接失败！";
	
	
	private byte[] cacheByte;
	private byte[] getCacheByte(int length) {
		if(cacheByte==null)
		{
			cacheByte = new byte[length];
		}
		return cacheByte;
	}
	
	/**
	 * 分块下载
	 */
	private boolean downloadBlockFileRetry(String url,FileOutputStream fileOutputStream,long totalSize,long startPos,long blockSize) {
		/*
		for(int i=0;i<3;i++)
		{
			if(downloadBlockFile(url,fileOutputStream,totalSize,startPos,blockSize))
			{
				return true;
			}
			else
			{
				try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
				}
			}
		}
		return false;
		*/
		return downloadBlockFile(url,fileOutputStream,totalSize,startPos,blockSize);
	}
	
	/**
	 * 分块下载
	 */
	private boolean downloadBlockFile(String url,FileOutputStream fileOutputStream,long totalSize,long startPos,long blockSize) {
		if(!SystemInfo.isNetworkAvailable(mContext))//当前无网络
		{
			type = DOWNLOAD_STATE_TYPE_NO_NETWORK;
			reason = DOWNLOAD_RESULT_REASON_NO_NETWORK;
			Tools.showLog("downloadBlockFile", reason);
			return false;
		}
		String sProperty = "bytes=" + startPos + "-";
        if (blockSize>0) {
            sProperty = sProperty + (startPos + blockSize - 1);
        }
		ArrayList<BasicHeader> headerList = new ArrayList<BasicHeader>();
		headerList.add(new BasicHeader("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"));//"*/*"
		headerList.add(new BasicHeader("Connection", "Keep-Alive"));
		headerList.add(new BasicHeader("RANGE", sProperty));
		HttpResponse response = null;
		if(!isInterrup)
		{
			if(httpRequest==null)
			{
				httpRequest = new HttpRequest(mContext);
				httpRequest.setConnectionTimeout(10000);
				httpRequest.setSoTimeout(20000);
				httpRequest.setRedirecting(true);
			}
			response = httpRequest.getUrlHeaderList(url, headerList);
		}
		if(response!=null&&response.getStatusLine()!=null)
		{
			int stateCode=response.getStatusLine().getStatusCode();
			if(stateCode == HttpStatus.SC_OK || stateCode==HttpStatus.SC_PARTIAL_CONTENT)
			{
				try {
					HttpEntity entity = response.getEntity();
					if(entity!=null)
					{
						InputStream is = entity.getContent();
						if(is!=null)//下载的文件大小正确
						{
							byte[] buf = getCacheByte(20480);//20*1024   20480
							int ch = -1;
							int finishSize = 0;
							while ((ch = is.read(buf)) != -1 && !isInterrup) {
								if(!isInterrup)
								{
									fileOutputStream.write(buf, 0, ch);
									fileOutputStream.flush();
									finishSize += ch;
								}
								else
								{
									return false;
								}
							}
							if(isInterrup)
							{
								return false;
							}
							if(blockSize == finishSize)
							{
								return true;
							}
						}
					}
				} catch (IOException e) {
				} catch (Exception e) {
				}
			}
		}
		return false;
	}
	
	private boolean download(String url,String savePath) {
		Tools.showLog("download", "download url="+url+" savePath="+savePath);
		boolean result = false;
		File file=new File(savePath);
		String saveDir = file.getParent();
		String saveName = file.getName();
		long startPos=0,block=blockSize;
		long downloadSize = 0;
		long totalSize = 0;
		if(!SystemInfo.isNetworkAvailable(mContext))//当前无网络
		{
			if(file.exists())
			{
				totalSize = file.length();
				if(totalSize>0)
				{
					downloadFileSize = totalSize;
					type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
					reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
					Tools.showLog("download", reason);
					return true;
				}
			}
			type = DOWNLOAD_STATE_TYPE_NO_NETWORK;
			reason = DOWNLOAD_RESULT_REASON_NO_NETWORK;
			Tools.showLog("download", reason);
			return false;
		}
		
		ArrayList<BasicHeader> headerList = new ArrayList<BasicHeader>();
		headerList.add(new BasicHeader("Accept", "*/*"));//"*/*"
		headerList.add(new BasicHeader("Connection", "Keep-Alive"));//"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*"
		headerList.add(new BasicHeader("RANGE", "bytes=0-9"));
		if(httpRequest==null)
		{
			httpRequest = new HttpRequest(mContext);
			httpRequest.setConnectionTimeout(10000);
			httpRequest.setSoTimeout(20000);
		}
		httpRequest.setRedirecting(false);
		HttpResponse response = httpRequest.getUrlHeaderList(url, headerList);
		
		if(response!=null&&response.getStatusLine()!=null)
		{
			int stateCode=response.getStatusLine().getStatusCode();
			Tools.showLog("download", "stateCode="+stateCode);
			if(stateCode == HttpStatus.SC_OK || stateCode==HttpStatus.SC_PARTIAL_CONTENT)
			{
				
			}
			else if(stateCode==HttpStatus.SC_MOVED_TEMPORARILY || stateCode==HttpStatus.SC_MOVED_PERMANENTLY)//跳转
			{
				Header header = response.getFirstHeader("Location");
				if(header!=null)
				{
					Tools.showLog("download", "StatusCode:"+stateCode+" - header name="+header.getName()+" value="+header.getValue());
					url = header.getValue();
					Tools.showLog("download", "jump url="+url);
					if(url!=null&&url.length()>0)
					{
						for(int i=0;i<5;i++)
						{
							response = httpRequest.getUrlHeaderList(url, headerList);
							if(response!=null&&response.getStatusLine()!=null)
							{
								stateCode=response.getStatusLine().getStatusCode();
								Tools.showLog("download", "stateCode="+stateCode);
								if(stateCode == HttpStatus.SC_OK || stateCode==HttpStatus.SC_PARTIAL_CONTENT)
								{
									break;
								}
								else if(stateCode==HttpStatus.SC_MOVED_TEMPORARILY || stateCode==HttpStatus.SC_MOVED_PERMANENTLY)//跳转
								{
									header = response.getFirstHeader("Location");
									if(header!=null)
									{
										Tools.showLog("download", "StatusCode:"+stateCode+" - header name="+header.getName()+" value="+header.getValue());
										url = header.getValue();
										Tools.showLog("download", "jump url="+url);
										if(url!=null&&url.length()>0)
										{
											
										}
										else
										{
											response = null;
											break;
										}
									}
									else
									{
										response = null;
										break;
									}
								}
								else
								{
									response = null;
									break;
								}
							}
							else
							{
								response = null;
								break;
							}
						}
					}
					else
					{
						response = null;
					}
				}
				else
				{
					response = null;
				}
			}
			else
			{
				response = null;
			}
		}
		
		try {
			if(response!=null&&response.getStatusLine()!=null)
			{
				int stateCode=response.getStatusLine().getStatusCode();
				if(stateCode == HttpStatus.SC_OK || stateCode==HttpStatus.SC_PARTIAL_CONTENT)
				{
					Tools.showLog("download", "begin to get totalSize");
					
					Header[] headerArr = response.getAllHeaders();
					if(headerArr!=null&&headerArr.length>0)
					{
						Header header;
						for(int i=0;i<headerArr.length;i++) {
							header = headerArr[i];
							if(header!=null)
							{
								Tools.showLog("download", "name="+header.getName()+" value="+header.getValue());
							}
						}
					}
					
					long contentLength = 0;
					
					Header headerContentRange = response.getFirstHeader("Content-Range");
					if(headerContentRange!=null)
					{
						Tools.showLog("download", "header!=null");
						String contentRange = headerContentRange.getValue();//contentRange=bytes 0-184319/9057633
						Tools.showLog("download", "contentRange="+contentRange);
						int index = contentRange.indexOf("/");
						if(index>=0)
						{
							Tools.showLog("download", "index>=0");
							String totalSizeStr = contentRange.substring(index+1);
							try {
								totalSize = Long.parseLong(totalSizeStr);
							} catch(NumberFormatException e) {
								
							}
							Tools.showLog("download", "totalSize = "+totalSize);
						}
						
						if(totalSize==0)
						{
							response = null;
						}
						Tools.showLog("download", "totalSize = "+totalSize);
					}
					else
					{
						Header headerContentLength = response.getFirstHeader("Content-Length");
						if(headerContentLength!=null)
						{
							String contentLengthStr = headerContentLength.getValue();
							Tools.showLog("download", "contentLengthStr="+contentLengthStr);
							try {
								contentLength = Long.parseLong(contentLengthStr);
								totalSize = contentLength;
							} catch(NumberFormatException e) {
								
							}
							Tools.showLog("download", "contentLength = "+contentLength);
						}
					}
					
					if(totalSize>0)
					{
						downloadFileSize = totalSize;
						downloadPhone = savePath.startsWith("/data/data/");
						if(file.exists())
						{
							if(file.length()==totalSize)
							{
								Tools.showLog("download", "downloadSucess for file.exists() savePath="+savePath+" url="+url+" file.length()="+file.length());
								type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
								reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
								Tools.showLog("download", reason);
								return true;
							}
							else//已经下载的文件已经被更新替换
							{
								Tools.showLog("download", "已经下载成功的文件已经过时，需要删除");
								file.delete();
							}
						}
						
						File tempfile = new File(savePath+TEMP_FILE_END);
						if(tempfile.exists())//下载过程中的临时文件已经存在
						{
							downloadSize = tempfile.length();
							if(downloadSize==totalSize)
							{
								Tools.showLog("download", "downloadSucess for file.exists() saveName="+saveName+" url="+url+" file.length()="+file.length());
								type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
								reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
								Tools.showLog("download", reason);
								tempfile.renameTo(file);
								return true;
							}
							else if(downloadSize>totalSize)//已经下载的文件已经被更新替换
							{
								Tools.showLog("download", "已经下载过的缓存文件已经过时，需要删除");
								tempfile.delete();
								downloadSize = 0;
							}
						}
						
						File fileDir = new File(saveDir);
						if(!fileDir.exists())
						{
							fileDir.mkdirs();
						}
						if(fileDir.exists()&&Tools.getDirAvailableSize(saveDir)>(totalSize-downloadSize))//目录存在并且剩余空间足够
						{
							
						}
						else
						{
							downloadSize = 0;
							sdcardPath = Tools.getSdcardPath(totalSize);
							if(sdcardPath==null)
							{
								downloadPhone = true;
								file = mContext.getFileStreamPath(saveName);
								mSavePath = file.getAbsolutePath();
								if(file.exists())
								{
									if(file.length()==totalSize)
									{
										Tools.showLog("download", "downloadSucess for file.exists() savePath="+savePath+" url="+url+" file.length()="+file.length());
										type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
										reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
										Tools.showLog("download", reason);
										return true;
									}
									else//已经下载的文件已经被更新替换
									{
										Tools.showLog("download", "已经下载成功的文件已经过时，需要删除");
										file.delete();
									}
								}
								tempfile = mContext.getFileStreamPath(saveName+TEMP_FILE_END);
								if(tempfile.exists())//下载过程中的临时文件已经存在
								{
									downloadSize = tempfile.length();
									if(downloadSize==totalSize)
									{
										Tools.showLog("download", "downloadSucess for file.exists() saveName="+saveName+" url="+url+" file.length()="+file.length());
										type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
										reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
										Tools.showLog("download", reason);
										tempfile.renameTo(file);
										return true;
									}
									else if(downloadSize>totalSize)//已经下载的文件已经被更新替换
									{
										Tools.showLog("download", "已经下载过的缓存文件已经过时，需要删除");
										tempfile.delete();
										downloadSize = 0;
									}
								}
							}
							else
							{
								downloadPhone = false;
								file = new File(sdcardPath+"/"+DEFAULT_SAVE_FILE_DIR+"/"+saveName);
								mSavePath = file.getAbsolutePath();
								if(file.exists())
								{
									if(file.length()==totalSize)
									{
										Tools.showLog("download", "downloadSucess for file.exists() savePath="+savePath+" url="+url+" file.length()="+file.length());
										type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
										reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
										Tools.showLog("download", reason);
										return true;
									}
									else//已经下载的文件已经被更新替换
									{
										Tools.showLog("download", "已经下载成功的文件已经过时，需要删除");
										file.delete();
									}
								}
								tempfile = new File(sdcardPath+"/"+DEFAULT_SAVE_FILE_DIR+"/"+saveName+TEMP_FILE_END);
								if(tempfile.exists())//下载过程中的临时文件已经存在
								{
									downloadSize = tempfile.length();
									if(downloadSize==totalSize)
									{
										Tools.showLog("download", "downloadSucess for file.exists() saveName="+saveName+" url="+url+" file.length()="+file.length());
										type = DOWNLOAD_STATE_TYPE_HAS_DOWNLOADED;
										reason = DOWNLOAD_RESULT_REASON_HAS_DOWNLOADED;
										Tools.showLog("download", reason);
										tempfile.renameTo(file);
										return true;
									}
									else if(downloadSize>totalSize)//已经下载的文件已经被更新替换
									{
										Tools.showLog("download", "已经下载过的缓存文件已经过时，需要删除");
										tempfile.delete();
										downloadSize = 0;
									}
								}
							}
						}
						
						if(contentLength==0)//支持断点续传
						{
							startPos=downloadSize;//断点续传的关键代码
						}
						else
						{
							startPos=0;
						}
						FileOutputStream fileOutputStream = null;
						if(!downloadPhone)
						{
							fileOutputStream = new FileOutputStream(tempfile,downloadSize>0&&contentLength==0);//new File(sdcardPath+FILE_SAVE_DIR);//Environment.getExternalStorageDirectory()+FILE_SAVE_DIR
						}
						else
						{
							int mode = Context.MODE_WORLD_READABLE|Context.MODE_WORLD_WRITEABLE;
							if(downloadSize>0&&contentLength==0)
							{
								mode |= Context.MODE_APPEND;
							}
							fileOutputStream = mContext.openFileOutput(saveName+TEMP_FILE_END, mode);//new FileOutputStream(tempfile);
						}
						
						if(downloadProgress!=null)
						{
							downloadProgress.downloadStart(mId, mUrl, mSavePath, downloadPhone, startPos, downloadFileSize, mDownloadInfo);
						}
						
						httpRequest.setRedirecting(true);
						result = true;
						while(startPos<totalSize)
						{
							if(isInterrup)
							{
								result = false;
								break;
							}
							if(contentLength==0)
							{
								if((totalSize-startPos)>=blockSize)
								{
									block = blockSize;
								}
								else
								{
									block = totalSize-startPos;
								}
							}
							else
							{
								block = contentLength;
							}
							if(downloadBlockFileRetry(url,fileOutputStream,totalSize,startPos,block))
							{
								startPos+=block;
								if(downloadProgress!=null)
								{
									downloadProgress.downloading(mId, mUrl, mSavePath, downloadPhone, startPos, totalSize, mDownloadInfo);
								}
								Tools.showLog("download", "downloading saveName="+saveName+" url="+url+" downsize="+startPos+" totalsize="+totalSize);
							}
							else
							{
								Tools.showLog("download", "downloading fail saveName="+saveName+" url="+url+" downsize="+startPos+" totalsize="+totalSize+" block="+block);
								result = false;
								break;
							}
							if(isInterrup)
							{
								result = false;
								break;
							}
						}
						if(result&&tempfile.length()>0)
						{
							tempfile.renameTo(file);
							mSavePath = file.getAbsolutePath();
						}
						else
						{
							result = false;
						}
						if(isInterrup)
						{
							return false;
						}
						if (fileOutputStream != null)
						{
							fileOutputStream.close();
							fileOutputStream = null;
						}
					}
				}
				else
				{
					response = null;
				}
			}
		} catch (Exception e) {
			
		}
		if(response == null)
		{
			type = DOWNLOAD_STATE_TYPE_CONNECT_FAIL;
			reason = DOWNLOAD_RESULT_REASON_CONNECT_FAIL;
			Log.e("download", reason);
		}
		return result;
	}
	
	public boolean downloadFile(String url,String savePath) {
		return downloadFile(null,url,savePath,null,null);
	}
	
	public boolean downloadFile(String url,String savePath,DownloadProgress progress) {
		return downloadFile(null,url,savePath,progress,null);
	}
	
	public boolean downloadFile(String id,String url,String savePath,DownloadProgress progress) {
		return downloadFile(id,url,savePath,progress,null);
	}
	
	public boolean downloadFile(String id,String url,String savePath,DownloadProgress progress,Object downloadInfo) {
		boolean result = false;
		isInterrup = false;
		mId=id;
		mUrl=url;
		mSavePath = savePath;
		if(progress!=null)
		{
			downloadProgress=progress;
		}
		if(downloadInfo!=null)
		{
			mDownloadInfo=downloadInfo;
		}
		if(downloadProgress!=null)
		{
			downloadProgress.downloadReady(id, url, downloadInfo);
		}
		if(url!=null&&url.length()>0&&savePath!=null&&savePath.length()>0)
		{
			if(!isInterrup)
			{
				for(int i=0;i<3&&!isInterrup;i++)
				{
					result = download(url,savePath);
					if(result)
					{
						break;
					}
					else
					{
						try {
							Thread.sleep(5000);
						} catch (InterruptedException e) {
						}
					}
				}
			}
		}
		else
		{
			
		}
		if(downloadProgress!=null)
		{
			if(result)
			{
				downloadProgress.downloadSucess(mId, mUrl, mSavePath, downloadPhone, downloadFileSize, type, reason, mDownloadInfo);
			}
			else
			{
				downloadProgress.downloadFail(mId, mUrl, mSavePath, downloadPhone, type, reason, mDownloadInfo);
			}
		}
		if(httpRequest!=null)
		{
			httpRequest.unInit();
			httpRequest = null;
			cacheByte = null;
		}
		return result;
	}
	
}
